#include "exprbinaria.h"

ExprBinaria::ExprBinaria(Expr *left, Expr *right, int fila, int col):Expr(fila,col)
{
    this->left=left;
    this->right=right;
}

Expr *ExprBinaria::getLeft()
{
    return this->left;
}

void ExprBinaria::setLeft(Expr *left)
{
    this->left = left;
}

Expr *ExprBinaria::getRight()
{
    return this->right;
}

void ExprBinaria::setRight(Expr *right)
{
    this->right = right;
}

void ExprBinaria::setis(int tokentype)
{
    TokenType tt;
    is_ = tt.returntokenstring(tokentype);
}

string ExprBinaria::is()
{
    return is_;
}

Tipo_ts *ExprBinaria::validarSemantica(Tabla_Simbolos *tabla_de_tipo, Tabla_Simbolos *tabla_de_varaible)
{

    Tipo_ts *I = this->getLeft()->validarSemantica(tabla_de_tipo,tabla_de_varaible);

    Tipo_ts *D = this->getRight()->validarSemantica(tabla_de_tipo,tabla_de_varaible);

    if(this->is_.compare("+")==0){
        if(I->is().compare("ENTERO") == 0){
            if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                return D;
            }else{
                stringstream out;
                out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                throw exception(out.str().c_str());
            }
        }else{
            if(I->is().compare("REAL") == 0){
                if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                    return I;
                }else{
                    stringstream out;
                    out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                    throw exception(out.str().c_str());
                }
            }else{
                if(I->is().compare("CADENA") == 0){
                    if(D->is().compare("CADENA")==0){
                        return I;
                    }else{
                        stringstream out;
                        out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                        throw exception(out.str().c_str());
                    }
                }else{
                    stringstream out;
                    out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                    throw exception(out.str().c_str());
                }
            }
        }
    }else{
        if(this->is_.compare("-")==0){
            if(I->is().compare("ENTERO") == 0){
                if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                    return D;
                }else{
                    stringstream out;
                    out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                    throw exception(out.str().c_str());
                }
            }else{
                if(I->is().compare("REAL") == 0){
                    if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                        return I;
                    }else{
                        stringstream out;
                        out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                        throw exception(out.str().c_str());
                    }
                }else{
                    stringstream out;
                    out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                    throw exception(out.str().c_str());

                }
            }
        }else{
            if(this->is_.compare("O")==0){
                if(I->is().compare("ENTERO") == 0){
                    if(D->is().compare("ENTERO")==0){
                        return I;
                    }else{
                        stringstream out;
                        out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                        throw exception(out.str().c_str());
                    }
                }else{
                    if(I->is().compare("BOOLEANO") == 0){
                        if(D->is().compare("BOOLEANO")==0){
                            return I;
                        }else{
                            stringstream out;
                            out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                            throw exception(out.str().c_str());
                        }
                    }else{
                        stringstream out;
                        out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                        throw exception(out.str().c_str());
                    }
                }
            }else{
                if(this->is_.compare("Y")==0){
                    if(I->is().compare("ENTERO") == 0){
                        if(D->is().compare("ENTERO")==0){
                            return I;
                        }else{
                            stringstream out;
                            out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                            throw exception(out.str().c_str());
                        }
                    }else{
                        if(I->is().compare("BOOLEANO") == 0){
                            if(D->is().compare("BOOLEANO")==0){
                                return I;
                            }else{
                                stringstream out;
                                out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                throw exception(out.str().c_str());
                            }
                        }else{
                            stringstream out;
                            out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                            throw exception(out.str().c_str());
                        }
                    }
                }else{
                    if(this->is_.compare("*")==0){
                        if(I->is().compare("ENTERO") == 0){
                            if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                                return D;
                            }else{
                                stringstream out;
                                out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                throw exception(out.str().c_str());
                            }
                        }else{
                            if(I->is().compare("REAL") == 0){
                                if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                                    return I;
                                }else{
                                    stringstream out;
                                    out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                    throw exception(out.str().c_str());
                                }
                            }else{
                                stringstream out;
                                out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                                throw exception(out.str().c_str());
                            }
                        }
                    }else{
                        if(this->is_.compare("/")==0){
                            if(I->is().compare("ENTERO") == 0){
                                if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                                    return D;
                                }else{
                                    stringstream out;
                                    out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                    throw exception(out.str().c_str());
                                }
                            }else{
                                if(I->is().compare("REAL") == 0){
                                    if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                                        return I;
                                    }else{
                                        stringstream out;
                                        out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                        throw exception(out.str().c_str());
                                    }
                                }else{
                                    stringstream out;
                                    out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                                    throw exception(out.str().c_str());
                                }
                            }
                        }else{
                            if(this->is_.compare("MOD")==0){
                                if(I->is().compare("ENTERO") == 0){
                                    if(D->is().compare("ENTERO")==0){
                                        return D;
                                    }else{
                                        stringstream out;
                                        out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                        throw exception(out.str().c_str());
                                    }
                                }else{
                                    stringstream out;
                                    out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                                    throw exception(out.str().c_str());
                                }
                            }else{
                                if(this->is_.compare("DIV")==0){
                                    if(I->is().compare("ENTERO") == 0){
                                        if(D->is().compare("ENTERO")==0){
                                            return D;
                                        }else{
                                            stringstream out;
                                            out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                            throw exception(out.str().c_str());
                                        }
                                    }else{
                                        stringstream out;
                                        out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                                        throw exception(out.str().c_str());
                                    }
                                }else{
                                    if(this->is_.compare("^")==0){
                                        if(I->is().compare("ENTERO") == 0){
                                            if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                                                return D;
                                            }else{
                                                stringstream out;
                                                out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                                throw exception(out.str().c_str());
                                            }
                                        }else{
                                            if(I->is().compare("REAL") == 0){
                                                if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                                                    return I;
                                                }else{
                                                    stringstream out;
                                                    out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                                    throw exception(out.str().c_str());
                                                }
                                            }else{
                                                stringstream out;
                                                out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                                                throw exception(out.str().c_str());

                                            }
                                        }
                                    }else{
                                        if(this->is_.compare("MAYOR")==0 || this->is_.compare("MENOR")==0 || this->is_.compare("MENORIGUAL")==0 || this->is_.compare("MAYORIGUAL")==0 || this->is_.compare("IGUAL")==0 || this->is_.compare("DISTINTO")==0){
                                            if(I->is().compare("ENTERO") == 0){
                                                if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){

                                                    return tabla_de_tipo->get("BOOLEANO")->getTipo() ;
                                                }else{
                                                    stringstream out;
                                                    out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                                    throw exception(out.str().c_str());
                                                }
                                            }else{
                                                if(I->is().compare("REAL") == 0){
                                                    if(D->is().compare("ENTERO")==0 || D->is().compare("REAL")==0){
                                                        return tabla_de_tipo->get("BOOLEANO")->getTipo() ;
                                                    }else{
                                                        stringstream out;
                                                        out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                                        throw exception(out.str().c_str());
                                                    }
                                                }else{
                                                    if(I->is().compare("CADENA") == 0){
                                                        if(D->is().compare("CADENA")==0){
                                                            return tabla_de_tipo->get("BOOLEANO")->getTipo() ;
                                                        }else{
                                                            stringstream out;
                                                            out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                                            throw exception(out.str().c_str());
                                                        }
                                                    }else{
                                                        if(I->is().compare("CARACTER") == 0){
                                                            if(D->is().compare("CARACTER")==0){
                                                                return tabla_de_tipo->get("BOOLEANO")->getTipo() ;
                                                            }else{
                                                                stringstream out;
                                                                out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                                                throw exception(out.str().c_str());
                                                            }
                                                        }else{
                                                            if(I->is().compare("BOOLEANO") == 0){
                                                                if(D->is().compare("BOOLEANO")==0){
                                                                    return tabla_de_tipo->get("BOOLEANO")->getTipo() ;
                                                                }else{
                                                                    stringstream out;
                                                                    out<<"Tipo de datos incompatibles// Fila:"<<this->getFila()<<endl;
                                                                    throw exception(out.str().c_str());
                                                                }
                                                            }else{
                                                                stringstream out;
                                                                out<<"Operacion No Valida// Fila:"<<this->getFila()<<endl;
                                                                throw exception(out.str().c_str());

                                                            }

                                                        }

                                                    }

                                                }
                                            }
                                        }else{
                                            stringstream out;
                                            out<<"Operacion no Soportada// Fila:"<<this->getFila()<<endl;
                                            throw exception(out.str().c_str());
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Codigo_Lugar ExprBinaria::generarCodigo(GenerarVariable* var,Tabla_Simbolos *tabla_de_tipo,Tabla_Simbolos *tabla_de_varaible)
{
    Tipo_ts *I = this->getLeft()->validarSemantica(tabla_de_tipo,tabla_de_varaible);
    Tipo_ts *D = this->getRight()->validarSemantica(tabla_de_tipo,tabla_de_varaible);
    Codigo_Lugar ret;
    Codigo_Lugar left= this->getLeft()->generarCodigo(var,tabla_de_tipo,tabla_de_varaible);
    Codigo_Lugar right= this->getRight()->generarCodigo(var,tabla_de_tipo,tabla_de_varaible);

    bool iscadL = true;
    bool iscadR = true;
    if(left.lugar.compare("")!=0){
       ret.codigo+=left.codigo;
    }
    if(right.lugar.compare("")!=0){
        ret.codigo+=right.codigo;
    }
    if(this->is_.compare("+")==0){
        if(this->getLeft()->is().compare("Literal_Cadena")==0 ||this->getRight()->is().compare("Literal_Cadena")==0 ||this->getLeft()->is().compare("Literal_Identificador")==0 ||this->getRight()->is().compare("Literal_Identificador")==0 ){

            string eti1,eti2;
            if(this->getLeft()->is().compare("Literal_Cadena")==0){
            int size = left.codigo.size()-1;
            QString n;
            n.setNum(size,10);
             eti1 = var->getNewVariable("str");
            ret.codigo += "char "+eti1+"["+n.toStdString()+"];\n";
            size--;
            n.setNum(size,10);
            ret.codigo += "strncpy("+eti1+","+left.codigo+","+n.toStdString()+");\n";
            ret.codigo += eti1+"["+n.toStdString()+"]='\\0';\n";
            }
            if(this->getRight()->is().compare("Literal_Cadena")==0){
            int size = right.codigo.size()-1;
            QString n;
            n.setNum(size,10);
             eti2 = var->getNewVariable("str");
            ret.codigo += "char "+eti2+"["+n.toStdString()+"];\n";
            size--;
            n.setNum(size,10);
            ret.codigo += "strncpy("+eti2+","+right.codigo+","+n.toStdString()+");\n";
            ret.codigo += eti2+"["+n.toStdString()+"]='\\0';\n";
            }
            if(this->getLeft()->is().compare("Literal_Identificador")==0){
                if(I->is().compare("CADENA")==0){
                    eti1 = left.codigo;
                }else{
                    iscadL=false;
                    left.codigo = left.codigo;
                }
            }
            if(this->getRight()->is().compare("Literal_Identificador")==0){
                if(D->is().compare("CADENA")==0){
                eti2 = right.codigo;
                }else{
                    iscadR=false;
                    right.codigo = right.codigo;
                }
            }

            if(iscadL!=false && iscadR!=false){
            if(left.lugar.compare("")==0){
            ret.codigo += "strcat("+eti1+","+eti2+");\n";
            ret.lugar = eti1;
            }else{
                ret.codigo += "strcat("+left.lugar+","+eti2+");\n";
                ret.lugar = left.lugar;
            }
            }else{
                ret.codigo = "("+left.codigo+" + "+right.codigo+")";
            }
        }else{
        ret.codigo = "("+left.codigo+" + "+right.codigo+")";
        }
    }else if(this->is_.compare("-")==0){
       ret.codigo =  "("+left.codigo+" - "+right.codigo+")";
    }else if(this->is_.compare("O")==0){
        ret.codigo =  "("+left.codigo+" || "+right.codigo+")";
    }else if (this->is_.compare("Y")==0){
        ret.codigo =  "("+left.codigo+" && "+right.codigo+")";
    }else if (this->is_.compare("*")==0){
       ret.codigo =  "("+left.codigo+" * "+right.codigo+")";
    }else if (this->is_.compare("/")==0){
        ret.codigo =  "("+left.codigo+" / "+right.codigo+")";
    }else if(this->is_.compare("MOD")==0){
        ret.codigo =  "("+left.codigo+" % "+right.codigo+")";
    }else if(this->is_.compare("DIV")==0){
        ret.codigo  =  "(int)("+left.codigo+" / "+right.codigo+")";
    }else if(this->is_.compare("^")==0){
        ret.codigo =  "((int)pow("+left.codigo+","+right.codigo+"))";
    }else if(this->is_.compare("MAYOR")==0){
        if(I->is().compare("CADENA")==0){
            ret.codigo = "(strcmp("+left.codigo+","+right.codigo+")>0)";
        }else{
        ret.codigo =  "("+left.codigo+" > "+right.codigo+")";
        }
    }else if(this->is_.compare("MENOR")==0){
        if(I->is().compare("CADENA")==0){
            ret.codigo = "(strcmp("+left.codigo+","+right.codigo+")<0)";
        }else{
        ret.codigo =  "("+left.codigo+" < "+right.codigo+")";
        }
    }else if(this->is_.compare("MENORIGUAL")==0){
        if(I->is().compare("CADENA")==0){
            ret.codigo = "(strcmp("+left.codigo+","+right.codigo+")<=0)";
        }else{
        ret.codigo =  "("+left.codigo+" <= "+right.codigo+")";
        }
    }else if(this->is_.compare("MAYORIGUAL")==0){
        if(I->is().compare("CADENA")==0){
            ret.codigo = "(strcmp("+left.codigo+","+right.codigo+")=0)";
        }else{
        ret.codigo =  "("+left.codigo+" >= "+right.codigo+")";
        }
    }else if(this->is_.compare("IGUAL")==0){
        if(I->is().compare("CADENA")==0){
            ret.codigo = "(strcmp("+left.codigo+","+right.codigo+")==0)";
        }else{
        ret.codigo =  "("+left.codigo+" == "+right.codigo+")";
        }
    }else if(this->is_.compare("DISTINTO")==0){
        if(I->is().compare("CADENA")==0){
            ret.codigo = "(strcmp("+left.codigo+","+right.codigo+")!=0)";
        }else{
        ret.codigo =  "("+left.codigo+" != "+right.codigo+")";
        }
    }

    return ret;

}
